using System;

public abstract class Reise
{
    // Passendes Delegate für die Storno-Algorithmen.
    public delegate double StornoAlgorithmus(Reise reise);

    // Algorithmen readonly, quasi Konstanten.
    public static readonly StornoAlgorithmus StrengerStornoAlgorithmus = 
        (reise) => reise.BestimmeTage() > 10 ? reise.BerechnePreis() * 0.25 : reise.BerechnePreis() * 0.75;

    public static readonly StornoAlgorithmus KulanterStornoAlgorithmus = 
        (reise) => reise.BestimmeTage() > 1 ? reise.BerechnePreis() * 0.25 : reise.BerechnePreis() * 0.5;

    protected double grundPreis;
    private readonly DateTime reiseBeginn;
    private StornoAlgorithmus stornoAlgorithmus;

    protected Reise(DateTime reiseBeginn, double grundPreis, StornoAlgorithmus stornoAlgorithmus)
    {
        this.reiseBeginn = reiseBeginn;
        this.grundPreis = grundPreis;
        this.stornoAlgorithmus = stornoAlgorithmus;
    }

    /// <summary>
    /// Ermittelt die Anzahl Tage bis zum Reisebeginn.
    /// </summary>
    public int BestimmeTage()
    {
        return (reiseBeginn - DateTime.Now).Days;
    }

    
    /// <summary>
    /// Kalkuliert mit unterschiedlichen Algorithmen den Preis der Reise.
    /// </summary>
    public abstract double BerechnePreis();

    /// <summary>
    /// Setzt den Storno Algorithmus.
    /// </summary>
    public void SetStornoAlgorithmus(StornoAlgorithmus stornoAlgorithmus)
    {
        this.stornoAlgorithmus = stornoAlgorithmus;
    }

    /// <summary>
    /// Berechnet die Stornogebühren und gibt diese zurück.
    /// </summary>
    public double BerechneStorno()
    {
        if (stornoAlgorithmus != null)
            return stornoAlgorithmus.Invoke(this);
        else return 0;
    }
}

class GoldReise : Reise
{
    // Bei GoldReisen kommt der kulante Stornoalgorithmus zum Einsatz
    public GoldReise(DateTime reiseBeginn, double grundPreis) : base (reiseBeginn, grundPreis, KulanterStornoAlgorithmus)
    {
    }

    public override double BerechnePreis()
    {
        return grundPreis * 1.75;
    }
}

class BronzeReise : Reise
{
    // Bei BronzeReisen kommt der strenge Stornoalgorithmus zum Einsatz (bei Stammkunden kann der Algorithmus auf den kulanten Stornoalgorithmus gesetzt werden)
    public BronzeReise(DateTime reiseBeginn, double grundPreis) : base(reiseBeginn, grundPreis, StrengerStornoAlgorithmus)
    {
    }

    
    public override double BerechnePreis()
    {
        return grundPreis * 1.25;
    }
}

